/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - core\types
// Copyright (c) 2014.  All Rights Reserved
//
// File:		AETypedObject.h
// Author:		Gianluca Belardelli
// Date:		21/02/2014
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AETYPEDOBJECT_H_
#define _AETYPEDOBJECT_H_

struct AE_REGISTER_CLASS;
#define AE_RUNTIME_CLASS(classname) ((AEType*)(&classname::class##classname))

class AETypedObject
{
	//friend class VArchive;
	
	AE_DECLARE_SERIAL_DLLEXP(AETypedObject, AE_COREDLLIMPEXP)

// Methods	
public:
	
	/// \brief
	///   Virtual function to serialize this object. The base implementation does not do anything.
	///
	/// This function is called by VArchive::ReadObject and VArchive::WriteObject when objects are fully (de-)serialized. Implement this function to read/write
	/// custom object data from/to the archive.
	///
	/// \param ar
	///   The archive that serializes this object
	///
	/// \sa VArchive::ReadObject
	/// \sa VArchive::WriteObject
	/// \sa VTypedObject::OnSerialized
	/// \sa VTypedObject::OnDeserializationCallback
	AE_COREDLLIMPEXP virtual void Serialize(VArchive& ar);
	
	/// \brief
	///   Overridable that is called after the serialization of this object has been completed (read and write). Additional object setup can be performed here
	///
	/// In contrast to OnDeserializationCallback this function is called right after Serialize of one object. The call of OnDeserializationCallback on the other hand
	/// is deferred until the archive is closed and then called on all relevant objects.
	///
	/// \param ar
	///   The archive where this object was serialized from
	///
	/// \sa VTypedObject::Serialize
	/// \sa VTypedObject::OnDeserializationCallback
	AE_COREDLLIMPEXP virtual void OnSerialized(VArchive& ar);
	
	/// \brief
	///   You can implement & call this function to do asserts for sanity checks 
	AE_COREDLLIMPEXP virtual void AssertValid();
	
	/// \brief
	///   Returns true if this class is the same or derived from the passed type
	AE_COREDLLIMPEXP VBool IsOfType(const VType *type) const;
	
	
	/// \brief
	///   Loops through the hierarchy and returns true if this class is the same
	///   or derived from the supplied class name.
	AE_COREDLLIMPEXP VBool IsOfType(const char *szClassName) const;
	
	/// \brief
	///   Virtual overridable that gets called when the object is created via VType::CreateInstance().
	/// 
	/// The serialization is not completed at that point, so OnDeserializationCallback might be
	/// called instead.
	AE_COREDLLIMPEXP virtual void Initialize();
	
	/// \brief
	///   Virtual overridable that notifies an object that it should be removed.
	/// 
	/// When this object is reference counted this function should not necessarily destroy the
	/// object, but at least remove it from all simulation groups.
	/// This function triggers the static OnObjectDisposed callback so application code can listen to all objects being disposed.
	/// 
	/// This base implementation must be called.
	AE_COREDLLIMPEXP virtual void DisposeObject();
	
	/// \brief
	///   Indicates whether the object has been disposed already.
	inline bool IsDisposed() const
	{
	return IsObjectFlagSet(VObjectFlag_Disposed);
	}
	
	/// \brief
	///   Indicates whether the object is currently being disposed
	inline bool IsDisposing() const
	{
	return IsObjectFlagSet(VObjectFlag_Disposing);
	}
	
	/// \brief
	///   Virtual overridable that gets called when a loading archive closes
	/// 
	/// At that point all objects in the serialization session already exist. (This is the difference between this function and overridable VTypedObject::OnSerialized).
	/// Entity classes can use this function to call their virtual InitFunction.
	/// The WantsDeserializationCallback function must also be overridden and return true.
	///
	/// Please note that the OnDeserializationCallback may also be called a) by vForge when it creates the native instances
	/// and b) by the engine's network manager when an object should be fully replicated. You can specify this when overriding
	/// the VTypedObject::WantsDeserializationCallback method by evaluating the m_eType variable in the passed context
	/// accordingly.
	///
	/// \param context
	///   Describes the source of the current deserialization process
	///
	/// \sa VTypedObject::WantsDeserializationCallback
	/// \sa VTypedObject::OnSerialized
	AE_COREDLLIMPEXP virtual void OnDeserializationCallback(const VSerializationContext &context)
	{
	}
	
	/// \brief
	///   Virtual overridable that indicates whether and when OnDeserializationCallback should be called for
	///   this object
	/// 
	/// The OnDeserializationCallback function is a useful mechanism but it requires that the object
	/// still exists when the archive gets closed.
	/// 
	/// The base implementation returns FALSE as it is not guaranteed that an object survives the
	/// loading process.
	///
	/// This method also defines whether the OnDeserializationCallback is called when vForge creates an
	/// object instance or the network manager replicates an object. Evaluate the passed context accordingly.
	///
	/// \param context
	///   Describes the source of the current deserialization process
	/// 
	/// \return
	///   TRUE to call OnDeserializationCallback at the end of the deserialization session. The default return value is FALSE
	///
	/// \sa OnDeserializationCallback
	AE_COREDLLIMPEXP virtual VBool WantsDeserializationCallback(const VSerializationContext &context)
	{
	return FALSE;
	}
	
	/// \brief
	///   Overridable that should be implemented for every derived class to add resource dependencies
	///   via snapshot.AddDependency.
	///
	/// \param snapshot
	///   The snapshot object that should be filled with dependency information
	///
	/// \sa VResourceSnapshot
	AE_COREDLLIMPEXP virtual void GetDependencies(VResourceSnapshot &snapshot) 
	{
	}
	
	
	/// \brief
	///   Sets the specific object flag (not overwriting other flags)
	inline void SetObjectFlag(VObjectFlags_e eFlag)
	{
	m_eObjectFlags |= eFlag;
	}
	
	/// \brief
	///   Clears the specific object flag (not overwriting other flags)
	inline void RemoveObjectFlag(VObjectFlags_e eFlag)
	{
	m_eObjectFlags &= (~eFlag);
	}
	
	/// \brief
	///   Tests whether the passed bit is set (If multiple bits are passed it tests whether any is set, i.e. the result of logical AND is not null)
	inline bool IsObjectFlagSet(VObjectFlags_e eFlag) const
	{
	return (m_eObjectFlags & eFlag) > 0;
	}
	
	/// \brief
	///   Returns the full bitmask
	inline int GetObjectFlags() const
	{
	return m_eObjectFlags;
	}
	
	/// \brief
	///   Sets the full bitmask - overwrite the status of all bits
	inline void SetObjectFlags(int iAllFlags)
	{
	m_eObjectFlags = iAllFlags;
	}
	
	/// \brief
	///   Indicates whether is object is currently in serialization process
	inline bool IsBusySerializing() const 
	{
	return IsObjectFlagSet(VObjectFlag_BusySerializing);
	}
	
	protected:
	int m_eObjectFlags; ///< Some internal flags (of enum type VObjectFlags_e)
	
	VType *m_pRegisteredAtType;  ///< Do not remove. Reserved for later use (m_pRegisteredAtType) [FR]
	
	VBASE_IMPEXP VTypedObject(); ///< Prevents direct instantiation.
	VBASE_IMPEXP virtual ~VTypedObject(); ///< Declares virtual destructor to get the right delete operator if different memory handlers/models are used.
	
	public:
	///
	/// @name Variable update
	/// @{
	///
	
	/// \brief
	///   Internal function to free memory that has been allocated by variables (e.g. strings).
	///
	/// This function is called by VTypedObject::DisposeObject
	AE_COREDLLIMPEXP void FreeOwnedData();
	
	/// \brief
	///   Return the Type's variable list. Same as GetTypeId()->m_pVarList
	AE_COREDLLIMPEXP VARIABLE_LIST *GetVariableList() const;
	
	/// \brief
	///   Overridable to set the a variable value.
	///
	/// The new variable value is always passed as a string value. Accordingly it has to be parsed if the underlying variable type
	/// is int or float. This base implementation handles this gracefully.
	///
	/// \param name
	///   The name of the variable to change
	///
	/// \param value
	///   A value string that represents the new variable value.
	///
	AE_COREDLLIMPEXP virtual bool SetVariable(const char * name, const char * value);
	
	/// \brief
	///   Overridable that can be implemented to respond to a variable changing on the object. The base implementation has no effect.
	///
	/// \param pVar
	///   The variable that will be changing.
	///
	/// \param value
	///   The value that will be set.
	AE_COREDLLIMPEXP virtual VVarChangeRes_e OnVariableValueChanging(VisVariable_cl *pVar, const char * value) { return VCHANGE_IS_ALLOWED; }
	
	/// \brief
	///   Overridable that can be implemented to respond to variable changes on the object. The base implementation is empty.
	///
	/// \param pVar
	///   The variable that has changed.
	///
	/// \param value
	///   The value that has been set.
	AE_COREDLLIMPEXP virtual void OnVariableValueChanged(VisVariable_cl *pVar, const char * value) {}
	
	#if defined(WIN32)
	
	/// \brief
	///   Overridable that is called by the editor to retrieve per-instance variable display hints. 
	///
	/// Implementing this function allow for dynamically show/hide variables in vForge or display in read-only mode.
	/// This function is only relevant in the editor. It is called by the editor when the specific parameter list node is openend 
	/// (e.g. EntityProperties for entity shape) or if a property in the list changes. For these events it is then called for every variable in the list.
	/// Accordingly this feature can be used to display specific variables dependent on the state of other variables. For instance, hide the 'SphereRadius'
	/// variable if 'CollisionType' is set to anything else but 'Sphere'.
	/// Note that this works on a per-instance basis.
	///
	/// \param pVariable
	///   Variable to retrieve dynamic display hints for
	///
	/// \param destInfo
	///   Structure that can be modified to affect the editor's displaying of the respective variable (read-only, hidden)
	///
	AE_COREDLLIMPEXP virtual void GetVariableAttributes(VisVariable_cl *pVariable, VVariableAttributeInfo &destInfo) {}
	
	/// \brief
	///   Overridable that is called by the editor to temporarily mark instances as part of one serialization session (VObjectFlag_InsideSerializationSession flag)
	AE_COREDLLIMPEXP virtual void SetMarkInsideSerializationSession(bool bStatus)
	{
	if (bStatus)
	  SetObjectFlag(VObjectFlag_InsideSerializationSession);
	else
	  RemoveObjectFlag(VObjectFlag_InsideSerializationSession);
	}
	
	#endif
	
	/// \brief
	///   Writes the current variable value into the passed string buffer
	AE_COREDLLIMPEXP virtual bool GetVariableValue(const char* name, char* value) const;
	
	/// \brief
	///   Looks up the type's variable by name
	AE_COREDLLIMPEXP VisVariable_cl *GetVariable(const char* name);
	
	/// \brief
	///   Returns the number of variables associated with the object's type
	AE_COREDLLIMPEXP int GetNumVariables() const;
	
	/// \brief
	///   Returns the name of the n-th variable where iIndex must be [0..GetNumVariables()-1]
	AE_COREDLLIMPEXP const char *GetVariableName(int iIndex) const;
	
	/// \brief
	///   Loads the default values for all variables in this object
	AE_COREDLLIMPEXP void InitDefaultValues();
	
	
	/// \brief empty base implementation
	static void VTypedObject_BuildVarList(class VARIABLE_LIST* pList) {}
	/// \brief empty base implementation
	static void VTypedObject_DeInitVarList(class VARIABLE_LIST* pList) {}
	
	/// \brief
	///   Static callback that is called for every typed object in its VTypedObject::DisposeObject function. The passed data object can be casted to VTypedObjectCallbackData
	static AE_COREDLLIMPEXP VCallback OnObjectDisposed;
	///
	/// @}
	///
private:

};
#endif // _AETYPEDOBJECT_H_
